/*
 * FIPS 180-1 compliant SHA-1 implementation,
 * by Christophe Devine <devine@cr0.net>;
 * this program is licensed under the GPL.
 */

#include "sha1.h"

#define GET_UINT32(n,b,i) \
 { \
  (n) = (unsigned int) ((unsigned char *) b)[(i)+3] \
   | (((unsigned int) ((unsigned char *) b)[(i)+2]) <<  8) \
   | (((unsigned int) ((unsigned char *) b)[(i)+1]) << 16) \
   | (((unsigned int) ((unsigned char *) b)[(i)]  ) << 24); \
 }

#define PUT_UINT32(n,b,i) \
 { \
  (((unsigned char *) b)[(i)+3]) = (unsigned char) (((n)      ) & 0xFF); \
  (((unsigned char *) b)[(i)+2]) = (unsigned char) (((n) >>  8) & 0xFF); \
  (((unsigned char *) b)[(i)+1]) = (unsigned char) (((n) >> 16) & 0xFF); \
  (((unsigned char *) b)[(i)]  ) = (unsigned char) (((n) >> 24) & 0xFF); \
 }

PUBLIC void SHA1Init( struct SHA1Context *ctx ) {
  ctx->total[0] = 0;
  ctx->total[1] = 0;
  ctx->state[0] = 0x67452301;
  ctx->state[1] = 0xEFCDAB89;
  ctx->state[2] = 0x98BADCFE;
  ctx->state[3] = 0x10325476;
  ctx->state[4] = 0xC3D2E1F0;
}

PRIVATE void sha1_process( struct SHA1Context *ctx, unsigned char data[64] ) {
  unsigned int temp, A, B, C, D, E, W[16];
  
  GET_UINT32( W[0],  data,  0 );
  GET_UINT32( W[1],  data,  4 );
  GET_UINT32( W[2],  data,  8 );
  GET_UINT32( W[3],  data, 12 );
  GET_UINT32( W[4],  data, 16 );
  GET_UINT32( W[5],  data, 20 );
  GET_UINT32( W[6],  data, 24 );
  GET_UINT32( W[7],  data, 28 );
  GET_UINT32( W[8],  data, 32 );
  GET_UINT32( W[9],  data, 36 );
  GET_UINT32( W[10], data, 40 );
  GET_UINT32( W[11], data, 44 );
  GET_UINT32( W[12], data, 48 );
  GET_UINT32( W[13], data, 52 );
  GET_UINT32( W[14], data, 56 );
  GET_UINT32( W[15], data, 60 );
  
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
  
#define R(t) \
 ( \
  temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[ t & 0x0F], ( W[t & 0x0F] = S(temp,1) ) \
 )
  
#define P(a,b,c,d,e,x) \
 { \
  e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
 }
  
  A = ctx->state[0];
  B = ctx->state[1];
  C = ctx->state[2];
  D = ctx->state[3];
  E = ctx->state[4];
  
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
  
  P( A, B, C, D, E, W[0]  );
  P( E, A, B, C, D, W[1]  );
  P( D, E, A, B, C, W[2]  );
  P( C, D, E, A, B, W[3]  );
  P( B, C, D, E, A, W[4]  );
  P( A, B, C, D, E, W[5]  );
  P( E, A, B, C, D, W[6]  );
  P( D, E, A, B, C, W[7]  );
  P( C, D, E, A, B, W[8]  );
  P( B, C, D, E, A, W[9]  );
  P( A, B, C, D, E, W[10] );
  P( E, A, B, C, D, W[11] );
  P( D, E, A, B, C, W[12] );
  P( C, D, E, A, B, W[13] );
  P( B, C, D, E, A, W[14] );
  P( A, B, C, D, E, W[15] );
  P( E, A, B, C, D, R(16) );
  P( D, E, A, B, C, R(17) );
  P( C, D, E, A, B, R(18) );
  P( B, C, D, E, A, R(19) );
  
#undef K
#undef F
  
#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1
  
  P( A, B, C, D, E, R(20) );
  P( E, A, B, C, D, R(21) );
  P( D, E, A, B, C, R(22) );
  P( C, D, E, A, B, R(23) );
  P( B, C, D, E, A, R(24) );
  P( A, B, C, D, E, R(25) );
  P( E, A, B, C, D, R(26) );
  P( D, E, A, B, C, R(27) );
  P( C, D, E, A, B, R(28) );
  P( B, C, D, E, A, R(29) );
  P( A, B, C, D, E, R(30) );
  P( E, A, B, C, D, R(31) );
  P( D, E, A, B, C, R(32) );
  P( C, D, E, A, B, R(33) );
  P( B, C, D, E, A, R(34) );
  P( A, B, C, D, E, R(35) );
  P( E, A, B, C, D, R(36) );
  P( D, E, A, B, C, R(37) );
  P( C, D, E, A, B, R(38) );
  P( B, C, D, E, A, R(39) );
  
#undef K
#undef F
  
#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
  
  P( A, B, C, D, E, R(40) );
  P( E, A, B, C, D, R(41) );
  P( D, E, A, B, C, R(42) );
  P( C, D, E, A, B, R(43) );
  P( B, C, D, E, A, R(44) );
  P( A, B, C, D, E, R(45) );
  P( E, A, B, C, D, R(46) );
  P( D, E, A, B, C, R(47) );
  P( C, D, E, A, B, R(48) );
  P( B, C, D, E, A, R(49) );
  P( A, B, C, D, E, R(50) );
  P( E, A, B, C, D, R(51) );
  P( D, E, A, B, C, R(52) );
  P( C, D, E, A, B, R(53) );
  P( B, C, D, E, A, R(54) );
  P( A, B, C, D, E, R(55) );
  P( E, A, B, C, D, R(56) );
  P( D, E, A, B, C, R(57) );
  P( C, D, E, A, B, R(58) );
  P( B, C, D, E, A, R(59) );
  
#undef K
#undef F
  
#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6
  
  P( A, B, C, D, E, R(60) );
  P( E, A, B, C, D, R(61) );
  P( D, E, A, B, C, R(62) );
  P( C, D, E, A, B, R(63) );
  P( B, C, D, E, A, R(64) );
  P( A, B, C, D, E, R(65) );
  P( E, A, B, C, D, R(66) );
  P( D, E, A, B, C, R(67) );
  P( C, D, E, A, B, R(68) );
  P( B, C, D, E, A, R(69) );
  P( A, B, C, D, E, R(70) );
  P( E, A, B, C, D, R(71) );
  P( D, E, A, B, C, R(72) );
  P( C, D, E, A, B, R(73) );
  P( B, C, D, E, A, R(74) );
  P( A, B, C, D, E, R(75) );
  P( E, A, B, C, D, R(76) );
  P( D, E, A, B, C, R(77) );
  P( C, D, E, A, B, R(78) );
  P( B, C, D, E, A, R(79) );
  
#undef K
#undef F
  
  ctx->state[0] += A;
  ctx->state[1] += B;
  ctx->state[2] += C;
  ctx->state[3] += D;
  ctx->state[4] += E;
}

PUBLIC void SHA1Update( struct SHA1Context *ctx, unsigned char *input, unsigned int length ) {
  unsigned int left, fill;
  
  if( ! length ) return;
  
  left = ( ctx->total[0] >> 3 ) & 0x3F;
  fill = 64 - left;
  
  ctx->total[0] += length <<  3;
  ctx->total[1] += length >> 29;
  
  ctx->total[0] &= 0xFFFFFFFF;
  ctx->total[1] += ctx->total[0] < ( length << 3 );
  
  if( left && length >= fill ) {
    memcpy( (void *) (ctx->buffer + left), (void *) input, fill );
    sha1_process( ctx, ctx->buffer );
    length -= fill;
    input  += fill;
    left = 0;
  }
  
  while( length >= 64 ) {
    sha1_process( ctx, input );
    length -= 64;
    input  += 64;
  }
  
  if( length ) {
    memcpy( (void *) (ctx->buffer + left), (void *) input, length );
  }
}

PRIVATE unsigned char sha1_padding[64] =
  {
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };

PUBLIC void SHA1Final( unsigned char digest[20], struct SHA1Context *ctx ) {
  unsigned int last, padn;
  unsigned char msglen[8];
  
  PUT_UINT32( ctx->total[1], msglen, 0 );
  PUT_UINT32( ctx->total[0], msglen, 4 );
  
  last = ( ctx->total[0] >> 3 ) & 0x3F;
  padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
  
  SHA1Update( ctx, sha1_padding, padn );
  SHA1Update( ctx, msglen, 8 );
  
  PUT_UINT32( ctx->state[0], digest,  0 );
  PUT_UINT32( ctx->state[1], digest,  4 );
  PUT_UINT32( ctx->state[2], digest,  8 );
  PUT_UINT32( ctx->state[3], digest, 12 );
  PUT_UINT32( ctx->state[4], digest, 16 );
}

PUBLIC void hash(void * data, int size, HashCode160 * hc) {
  struct SHA1Context ctx;
  
  SHA1Init( &ctx );
  SHA1Update( &ctx, data, size);
  SHA1Final( hc->data, &ctx );  
}


